{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 在测试视频(OpenCV安装目录\\sources\\samples\\data)上，使用基于混合高斯模型的背景提取算法，提取前景并显示(显示二值化图像，前景为白色)。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "\n",
    "cap = cv.VideoCapture(\"./vtest.avi\")\n",
    "fgbg = cv.createBackgroundSubtractorMOG2()\n",
    "\n",
    "while True:\n",
    "    ret, frame = cap.read()\n",
    "    if not ret:\n",
    "        break\n",
    "    fgmask = fgbg.apply(frame)  #获取前景\n",
    "    bgimage = fgbg.getBackgroundImage()  #获取背景景\n",
    "\n",
    "    element = cv.getStructuringElement(cv.MORPH_CROSS, (3, 3))  # 形态学去噪算子\n",
    "    fgmask = cv.morphologyEx(fgmask, cv.MORPH_OPEN, element)  # 开运算去噪\n",
    "\n",
    "    cv.imshow('frame', fgmask)\n",
    "    cv.imshow('background', bgimage)\n",
    "    key = cv.waitKey(1) & 0xFF\n",
    "    # 按'q'健退出循环\n",
    "    if key == ord('q'):\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果:  \n",
    "![背景建模](http://px71ub40t.bkt.clouddn.com/%E8%83%8C%E6%99%AF%E5%BB%BA%E6%A8%A1.gif)   \n",
    "\n",
    "### 2. 在1基础上，将前景目标进行分割，进一步使用不同颜色矩形框标记，并在命令行窗口中输出每个矩形框的位置和大小。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "\n",
    "cap = cv.VideoCapture(\"./vtest.avi\")\n",
    "fgbg = cv.createBackgroundSubtractorMOG2()\n",
    "thresh = 200\n",
    "\n",
    "while True:\n",
    "    ret, frame = cap.read()\n",
    "    if not ret:\n",
    "        break\n",
    "    fgmask = fgbg.apply(frame)\n",
    "    _, fgmask = cv.threshold(fgmask, 30, 0xff, cv.THRESH_BINARY)\n",
    "\n",
    "    bgImage = fgbg.getBackgroundImage()\n",
    "    bin,cnts,hier = cv.findContours(fgmask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)\n",
    "    count = 0\n",
    "    for c in cnts:\n",
    "        area = cv.contourArea(c)\n",
    "        if(area < thresh):\n",
    "            continue\n",
    "        count += 1\n",
    "        x,y,w,h = cv.boundingRect(c)\n",
    "        cv.rectangle(frame, (x, y), (x+w, y+h), (0,0xff,0), 2)\n",
    "    print(\"共检测到\",count, \"个目标\")\n",
    "    print(\"目标位置\",x, \",\", y)\n",
    "    print(\"目标大小\",area, \"\\n\")\n",
    "    cv.imshow(\"frame\", frame)\n",
    "    cv.imshow(\"background\", bgImage)\n",
    "\n",
    "    key = cv.waitKeyEx(30)\n",
    "    if key == 27:\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：\n",
    "![背景建模](http://px71ub40t.bkt.clouddn.com/%E8%83%8C%E6%99%AF%E5%BB%BA%E6%A8%A11.gif)   \n",
    "\n",
    "### 3. 安装ImageWatch，并在代码中通过设置断点，观察处理中间结果图像。  \n",
    "Visual Studio2019安装Image Watch2019观察米粒图像滤波时的中间结果图像示例：  \n",
    "![ImageWatch](http://px71ub40t.bkt.clouddn.com/imageWatch.png) \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "扩展作业： \n",
    "### 4. 使用光流估计方法，在前述测试视频上计算特征点，进一步进行特征点光流估计。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "\n",
    "feature_params = dict(maxCorners = 100,\n",
    "                      qualityLevel = 0.3,\n",
    "                      minDistance = 7,\n",
    "                      blockSize = 7)\n",
    "lk_params = dict(winSize = (15,15),\n",
    "                 maxLevel = 2,\n",
    "                 criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))\n",
    "\n",
    "cap = cv.VideoCapture(\"./vtest.avi\")\n",
    "\n",
    "ret, prev = cap.read()\n",
    "prevGray = cv.cvtColor(prev, cv.COLOR_BGR2GRAY)\n",
    "p0 = cv.goodFeaturesToTrack(prevGray, mask=None, **feature_params)\n",
    "\n",
    "while True:\n",
    "    ret, frame = cap.read()\n",
    "    if not ret:\n",
    "        break\n",
    "\n",
    "    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)\n",
    "    p1, st, err = cv.calcOpticalFlowPyrLK(prevGray, gray, p0, None, **lk_params)\n",
    "\n",
    "    goodPoints = p1[st == 1]\n",
    "    goodPrevPoints = p0[st == 1]\n",
    "\n",
    "    res = frame.copy()\n",
    "    drawColor = (0,0,255)\n",
    "    for i, (cur, prev) in enumerate(zip(goodPoints, goodPrevPoints)):\n",
    "        x0, y0 = cur.ravel()\n",
    "        x1, y1 = prev.ravel()\n",
    "        cv.line(res, (x0, y0), (x1, y1), drawColor)\n",
    "        cv.circle(res, (x0, y0), 3, drawColor)\n",
    "        \n",
    "    prevGray = gray.copy()\n",
    "    p0 = goodPoints.reshape(-1, 1, 2)\n",
    "\n",
    "    cv.imshow(\"result\", res)\n",
    "\n",
    "    key = cv.waitKey(30)\n",
    "    if key == 27:\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：\n",
    "![背景建模](http://px71ub40t.bkt.clouddn.com/%E8%83%8C%E6%99%AF%E5%BB%BA%E6%A8%A12.gif) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
